import 'package:flutter_app/app/models/download.dart';
import 'package:flutter_app/app/providers/db_provider.dart';
// import 'package:flutter_app/app/providers/downloader_provider.dart';
import 'package:sqflite/sqflite.dart';

import '/app/controllers/controller.dart';
import 'package:flutter/widgets.dart';
import 'dart:io';
import 'package:ffmpeg_kit_flutter_new/ffmpeg_kit.dart';
import 'package:nylo_framework/nylo_framework.dart';
import 'package:flutter/foundation.dart';
import 'package:path_provider/path_provider.dart';
import 'package:ffmpeg_kit_flutter_new/return_code.dart';

class DownloaderController extends Controller {
  static final DownloaderController _instance =
      DownloaderController._internal();

  factory DownloaderController() => _instance;

  DownloaderController._internal();

  final DbProvider _dbProvider = DbProvider();
  // final DownloaderProvider _downloaderProvider = DownloaderProvider();
  final Map<int, CancelToken> _activeDownloads = {};
// 添加一个暂停状态标志
  final Map<int, bool> _pausedFlags = {};

  Future<Database> get database async => await _dbProvider.database;
  @override
  construct(BuildContext context) {
    super.construct(context);
  }

  Future<String> downloadVideo(
      String site, String url, String name, String movie) async {
    var tasks = await getTasks();
    // 首先确定任务是否存在
    for (var task in tasks) {
      if (task.url == url) {
        debugPrint('任务已存在，无需重复下载');

        return '任务已存在，无需重复下载';
      }
    }

    debugPrint('开始下载: ${site} ${name}');

    Download task = Download(
        site: site,
        url: url,
        name: name,
        savePath: "",
        segments: [],
        downloadIndex: 0,
        status: DownloadStatusPending,
        progress: 0,
        movie: movie,
        createdAt: DateTime.now().toDateString());

    // 添加数据库任务
    int taskId = await createTask(task);
    final dir = await (defaultTargetPlatform == TargetPlatform.android
        ? getExternalStorageDirectory()
        : getApplicationDocumentsDirectory());
    debugPrint('即将下载到目录: ${dir?.path}/Downloads');
    // 接下来开始下载，并实时更新数据库状态
    _downloadM3u8(url, '${dir?.path}/Downloads', name, taskId);

    return "开始下载${name}";
  }

  // 继续下载
  Future<void> resumeDownload(int taskId) async {
    final task = (await getTasks()).firstWhere((t) => t.id == taskId);
    if (task.status == DownloadStatusPaused) {
      final dir = await (defaultTargetPlatform == TargetPlatform.android
          ? getExternalStorageDirectory()
          : getApplicationDocumentsDirectory());
      debugPrint('即将下载到目录: ${dir?.path}/Downloads');

      // _pausedFlags  删除  key
      _pausedFlags.remove(taskId);

      // 恢复下载逻辑
      _downloadM3u8(task.url, '${dir?.path}/Downloads', task.name, taskId);
    }
  }

  /// 处理m3u8视频流下载
  /// 1. 下载m3u8播放列表
  /// 2. 解析并下载所有.ts片段
  /// 3. 合并所有片段为一个完整文件
  Future<String> _downloadM3u8(
      String url, String dirPath, String fileName, int taskId) async {
    final cancelToken = CancelToken();
    _activeDownloads[taskId] = cancelToken;
    try {
      debugPrint('Starting m3u8 download for: $url');
      final dio = Dio();

      // Ensure Downloads directory exists
      final downloadsDir = Directory(dirPath);
      if (!await downloadsDir.exists()) {
        await downloadsDir.create(recursive: true);
        debugPrint('Created downloads directory: ${downloadsDir.path}');
      }

      final tempDir =
          await Directory('$dirPath/temp_$fileName').create(recursive: true);
      debugPrint('Created temp directory: ${tempDir.path}');

      final task = (await getTasks()).firstWhere((t) => t.id == taskId);

      task.status = DownloadStatusDownloading;
      await updateTask(task);

      // 1. Download m3u8 playlist
      final playlistPath = '${tempDir.path}/playlist.m3u8';
      debugPrint('下载m3u8播放列表:($url)到路径:$playlistPath');
      await dio.download(url, playlistPath, cancelToken: cancelToken);
      debugPrint('m3u8播放列表下载完成: $playlistPath');
      // 2. 解析m3u8文件，获取所有片段的URL
      final playlist = await File(playlistPath).readAsString();
      final segmentUrls = await _parseSegmentUrls(playlist, url);
      debugPrint('切片长度: ${segmentUrls.length}');

      // 创建文件列表文件,记录ts文件路径
      final concatFile = File('${tempDir.path}/file_list.txt');
      final concatSink = concatFile.openWrite();

      // 下载所有片段
      for (var i = 0; i < segmentUrls.length; i++) {
        if (_pausedFlags.containsKey(taskId)) {
          debugPrint('下载任务已暂停，中断下载循环');
          task.status = DownloadStatusPaused; // 明确设置暂停状态
          await updateTask(task);
          return "下载已暂停";
        }
        NyLogger.dump(_pausedFlags, "_pausedFlags");

        final segmentPath = '${tempDir.path}/segment_$i.ts';
        debugPrint(
            '开始下载切片进度(${i + 1}/${segmentUrls.length})----${segmentUrls[i]}');
        // 检查segmentPath是否已经存在
        if (await File(segmentPath).exists()) {
          debugPrint('切片$segmentPath已存在，跳过下载');
          continue;
        }

        await dio.download(
          segmentUrls[i],
          segmentPath,
          cancelToken: cancelToken,
          onReceiveProgress: (received, total) async {
            if (total > 0 && !_pausedFlags.containsKey(taskId)) {
              final segmentProgress = (i / segmentUrls.length) * 100;
              final currentProgress =
                  (received / total) * (100 / segmentUrls.length);
              final totalProgress = segmentProgress + currentProgress;
              task.progress = totalProgress.toInt();
              await updateTask(task);
            }
          },
        );

        if (_pausedFlags.containsKey(taskId)) {
          debugPrint('下载因暂停而中断，不执行合并操作');
          return "下载已暂停";
        }
        debugPrint('下载第${i + 1}切片到$segmentPath');

        // 每个切片下载完成后，也更新进度
        task.progress = ((i + 1) / segmentUrls.length * 100).toInt();
        task.downloadIndex = i;
        await updateTask(task);

        //
        concatSink.write("file $segmentPath\n");
      }

      await concatSink.close();
      // 合并切片内容为一个完整文件
      final outputPath = '$dirPath/${fileName.replaceAll('.m3u8', '.mp4')}';
      debugPrint('所有切片下载完成. 切片总长度: ${segmentUrls.length}');
      debugPrint('即将合并切片数据到:$outputPath');

      try {
        // 构建FFmpeg命令
        // 使用concat协议合并TS文件并转换为MP4
        final command =
            '-y -f concat -safe 0 -i "${concatFile.path}" -c copy "${outputPath}"';
        // 执行FFmpeg命令
        final session = await FFmpegKit.execute(command);

        //  处理执行结果
        final returnCode = await session.getReturnCode();
        final failStackTrace = await session.getFailStackTrace();

        if (ReturnCode.isSuccess(returnCode)) {
          // 更新任务状态为完成
          task.status = DownloadStatusCompleted;
          task.progress = 100;
          task.savePath = outputPath;
          await updateTask(task);
        } else if (ReturnCode.isCancel(returnCode)) {
          NyLogger.error('FFmpeg conversion cancelled');
        } else {
          NyLogger.error('FFmpeg conversion failed: $failStackTrace');
        }

        // 打印日志
        final logs = await session.getAllLogs();
        for (final log in logs) {
          NyLogger.info(log.getMessage());
        }

        //   final outputFile = await File(outputPath).create(recursive: true);
        //   final sink = outputFile.openWrite(mode: FileMode.write);

        //   for (var i = 0; i < segmentUrls.length; i++) {
        //     final segmentPath = '${tempDir.path}/segment_$i.ts';
        //     final segmentFile = File(segmentPath);
        //     sink.add(await segmentFile.readAsBytes());
        //     debugPrint('合并第${i + 1}切片到输出文件: $outputFile');
        //   }

        //   await sink.flush();
        //   await sink.close();
        //   debugPrint('成功合并切片');

        //   // 更新任务状态为完成
        task.status = DownloadStatusCompleted;
        task.progress = 100;
        task.savePath = outputPath;
        await updateTask(task);
        //删除临时文件
        await tempDir.delete(recursive: true);
        debugPrint('M3U8 文件成功下载到: $outputPath');
        return outputPath;
      } catch (e) {
        debugPrint('Segment concatenation error: $e');
        // Keep temp files for debugging
        return 'm3u8_${DateTime.now().millisecondsSinceEpoch}';
      }
    } on DioException catch (e) {
      if (e.type == DioExceptionType.cancel) {
        // 如果是取消异常，检查是否是暂停导致的
        if (_pausedFlags.containsKey(taskId)) {
          debugPrint('片段下载被暂停');
          return "下载已暂停";
        }
      }
      rethrow;
    } catch (e, stackTrace) {
      debugPrint('M3U8 download error: $e');
      debugPrint('Stack trace: $stackTrace');
      rethrow;
    }
  }

  /// 解析m3u8播放列表，获取所有.ts片段的URL
  /// 支持嵌套的m3u8播放列表
  Future<List<String>> _parseSegmentUrls(
      String playlist, String baseUrl) async {
    final basePath = baseUrl.substring(0, baseUrl.lastIndexOf('/') + 1);
    final lines = playlist.split('\n');
    final segments = <String>[];

    for (var i = 0; i < lines.length; i++) {
      final line = lines[i].trim();
      if (line.startsWith('#EXT-X-STREAM-INF')) {
        // This is a master playlist with variants
        if (i + 1 < lines.length) {
          final variantUrl = lines[i + 1].trim();
          if (variantUrl.endsWith('.m3u8')) {
            // Download and parse nested playlist
            final dio = Dio();
            final nestedUrl = variantUrl.startsWith('http')
                ? variantUrl
                : basePath + variantUrl;
            debugPrint('Downloading nested playlist: $nestedUrl');
            final response = await dio.get(nestedUrl);
            final nestedSegments =
                await _parseSegmentUrls(response.data.toString(), nestedUrl);
            segments.addAll(nestedSegments);
          }
        }
      } else if (line.endsWith('.ts') && !line.startsWith('#')) {
        // Direct TS segment
        segments.add(line.startsWith('http') ? line : basePath + line);
      }
    }

    return segments;
  }

  // 获取任务
  getTasks() async {
    var db = await database;
    final maps = await db.query(_dbProvider.downloadsTable);
    return maps.map((map) => Download.fromJson(map)).toList();
  }

  // 创建任务
  createTask(Download task) async {
    var db = await database;
    NyLogger.dump(task.id, 'id');
    NyLogger.dump(task.site, 'name');
    NyLogger.dump(task.name, 'name');
    NyLogger.dump(task.url, 'url');
    NyLogger.dump(task.savePath, 'savePath');
    NyLogger.dump(task.progress, 'progress');
    NyLogger.dump(task.segments, 'segments');
    NyLogger.dump(task.downloadIndex, 'downloadIndex');
    NyLogger.dump(task.status, 'status');
    NyLogger.dump(task.movie, 'movie');
    NyLogger.dump(task.createdAt, 'createdAt');

    return await db.insert(_dbProvider.downloadsTable, task.toJson());
  }

  // 创建任务
  createTask2(Download task) async {
    var db = await database;
    NyLogger.dump(task.id, 'id');
    NyLogger.dump(task.site, 'name');
    NyLogger.dump(task.name, 'name');
    NyLogger.dump(task.url, 'url');
    NyLogger.dump(task.savePath, 'savePath');
    NyLogger.dump(task.progress, 'progress');
    NyLogger.dump(task.createdAt, 'createdAt');

    return await db.insert(_dbProvider.downloadsTable, task.toJson());
  }

  // 更新任务
  updateTask(Download task) async {
    final db = await database;
    return await db.update(
      _dbProvider.downloadsTable,
      task.toJson(),
      where: 'id = ?',
      whereArgs: [task.id],
    );
  }

  // 删除任务
  deleteTask(Download task) async {
    final db = await database;
    await db.delete(
      _dbProvider.downloadsTable,
      where: 'id = ?',
      whereArgs: [task.id],
    );
    // 取消下载
    _activeDownloads[task.id]?.cancel("download paused");
    _activeDownloads.remove(task.id);
    // 删除本地文件
    var localfile = task.savePath;
    if (localfile != null && localfile.isNotEmpty) {
      var file = File(localfile);
      if (await file.exists()) {
        await file.delete();
      }
    }
  }

  // 修改暂停方法
  Future<void> pauseTask(int id) async {
    if (_pausedFlags.containsKey(id)) {
      print("object id: $id 已经暂停");
      return; // 已经处于暂停状态
    }

    // 设置暂停标志
    _pausedFlags[id] = true;

    final db = await database;
    await db.update(
      _dbProvider.downloadsTable,
      {"status": DownloadStatusPaused},
      where: "id = ?",
      whereArgs: [id],
    );

    // 取消下载
    _activeDownloads[id]?.cancel("download paused");
    _activeDownloads.remove(id);

    debugPrint("任务${id}已暂停");
  }
}
